package com.dd.keel.core.framework.protocol;


import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dd.keel.core.common.utils.ByteUtil;
import com.dd.keel.core.common.utils.Crc32;
import com.dd.keel.core.common.utils.FileUtil;

/**
 * Decode the request
 * @author Kevin.XU
 *
 */
public class SoaProtocolDecoder extends CumulativeProtocolDecoder{
	
	final static private Logger LOGGER = LoggerFactory.getLogger(SoaProtocolDecoder.class);
	
	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception
	{
		int avaliable_byte_count = in.remaining();
		if( avaliable_byte_count >= SoaMsg.MESSAGE_HEADER_LENGTH )
		{
			byte[] temp_byte_array = new byte[4];
			byte[] header_bytes = new byte[SoaMsg.MESSAGE_HEADER_LENGTH];
			int offset = 0;
			int position = in.position(); //record current position
			long crc = 0;
			long identifier = 0;
			long length = 0;
			byte type = 0;
			//read header
			in.get(header_bytes, 0, SoaMsg.MESSAGE_HEADER_LENGTH);
			//read 'crc'
			crc = ByteUtil.fourbyte2long(header_bytes, offset);
			offset += 4;
			//read 'identifier'
			identifier = ByteUtil.fourbyte2long(header_bytes, offset);
			offset += 4;
			//read 'length'
			length = ByteUtil.fourbyte2long(header_bytes, offset);
			offset += 4;
			//read 'type'
			type = header_bytes[offset];
			//read 'body'
            if(avaliable_byte_count-SoaMsg.MESSAGE_HEADER_LENGTH >= length)
            {
                if(length>5120) LOGGER.trace( "SoaProtocolDecoder :: message body length = {}", length);
                byte[] message_body = new byte[(int)length];   //basically sure that no losing data
                in.get(message_body);
                //crc32 check
                if(crc>0){
                    byte[] content = new byte[SoaMsg.MESSAGE_HEADER_LENGTH + (int)length - 4];
                    System.arraycopy(header_bytes, 4, content, 0, SoaMsg.MESSAGE_HEADER_LENGTH-4);
                    System.arraycopy(message_body, 0, content, SoaMsg.MESSAGE_HEADER_LENGTH-4, (int)length);
                    long crc_computed = Crc32.crc32(content);
                    if(crc_computed!=-1 && crc_computed != crc){
                    	String tempFile = FileUtil.retrieveTempFilepath("dd.dat");
                    	FileUtil.writeByteToFile(content, tempFile);
                    	LOGGER.error("invoke service failed : crc check failed , crc = {}, crc_computed = {}",crc,crc_computed);
                    	session.close(false);
                    	return false;
                    }
                }
                SoaMsg messageDatagram = new SoaMsg(crc,identifier,length,type,message_body);
                out.write(messageDatagram);
                return true;
            }
            else
            {
            	LOGGER.trace( "SoaProtocolDecoder :: have read header, but have not read body, need more data" );
            	in.position(position);
            	return false;
            }
		}
		else
		{
			LOGGER.debug( "SoaProtocolDecoder :: have not read header, need more data" );
			return false;
		}
	}
	
}
